package yawning.mew.cat;

import yawning.mew.ProcEffect.Trigger;
import yawning.mew.cat.CatModelSimState.CatTargetData;
import yawning.mew.character.CharacterModel.AttackResult;
import yawning.mew.sim.SimulationAction;
import yawning.mew.sim.SimulationTarget;

public class RavageAction implements SimulationAction {
	CatModelSimState mState;
	private SimulationTarget mTarget;
	private CatTargetData mTargetData;
	private String mTargetName;
	boolean mDidHardCastRavage = false;
	boolean mDidStampedeRavage = false;

	RavageAction(CatModelSimState state, CatTargetData targetData) {
		mState = state;
		mTarget = targetData.getSimulationTarget();
		mTargetData = targetData;
		mTargetName = mTarget.getTarget().getName();
	}

	@Override
	public double perform() {
		boolean isFromStealth = false;
		boolean isStampedeUp = mState.mStampedeEv.isUp();
		double pBonusCrit = 0.0;
		int cost;

		// Stampede reduces energy cost by 50% per talent point.
		if (isStampedeUp) {
			cost = mState.getEnergyCost(mState.mModel.ravageCostStampede);
		} else {
			if (mState.isInCombat()) return SimulationAction.ACTION_FAIL; // Without Stampede, can't mid-combat Ravage.
			if (mTargetData.mCanParry) return SimulationAction.ACTION_FAIL;	// Without Stampede, this has a position requirement.

			cost = mState.getEnergyCost(mState.mModel.ravageCost);
			isFromStealth = true;
		}

		if (mState.getEnergy() < cost && !mState.mOocEv.isUp()) return SimulationAction.ACTION_FAIL;

		if (isFromStealth) mDidHardCastRavage = true; else mDidStampedeRavage = true;

		int prevEnergy = mState.getEnergy(); int prevCps = mState.getComboPoints();

		// Predatory Strikes
		if (mState.mSimEngine.getSimTime() / mState.mSimEngine.getEndTime() < 0.2) {
			pBonusCrit = mState.mModel.druid.getTalent(CatModel.PREDATORYSTRIKES) * 0.25;
		}

		AttackResult result;
		if (mTargetData.mCanParry) {
			result = (isFromStealth) ? mState.mModel.getYellowStealthResult(pBonusCrit) : mState.mModel.getFrontalYellowResult(pBonusCrit);
		} else {
			result = (isFromStealth) ? mState.mModel.getYellowStealthResult(pBonusCrit) : mState.mModel.getYellowResult(pBonusCrit);
		}

		if (result == AttackResult.MISS) {
			cost = (int) Math.round(cost * 0.2);
			mNrRavageMiss++;

			if (mState.mIsLogging) mState.mLog.log("Ravage: %s MISS\n", mTargetName);
		} else if (result == AttackResult.DODGE) {
			cost = (int) Math.round(cost * 0.2);
			mNrRavageDodge++;

			if (mState.mIsLogging) mState.mLog.log("Ravage: %s DODGE\n", mTargetName);
		} else if (result == AttackResult.PARRY) {
			cost = (int) Math.round(cost * 0.2);
			mNrRavageParry++;

			if (mState.mIsLogging) mState.mLog.log("Ravage: %s PARRY\n", mTargetName);
		} else {
			double damage = mState.mModel.getWeaponDamage() * mState.mModel.levelDep.getRavageMult() + mState.mModel.levelDep.getRavageDmg();

			if (result == AttackResult.CRIT) {
				mNrRavageCrit++;
				damage *= mState.mModel.multCrit;
			} else {
				mNrRavageHit++;
			}

			damage *= mState.getDirectDamageMult();
			mRavageDamage += Math.round(damage);

			if (mState.mIsLogging) mState.mLog.log("Ravage: %s %s Damage: %d\n", mTargetName, result, Math.round(damage));

			if (result == AttackResult.CRIT) mState.mSimEngine.triggerProc(mTarget, Trigger.YELLOWCRIT); else mState.mSimEngine.triggerProc(mTarget, Trigger.YELLOW);

			mState.onCpGenerator(result == AttackResult.CRIT);

			// Only Ravage! that actually lands consumes Stampede.
			mState.mStampedeEv.onRavage();
		}

		if (mState.mTigersFuryEv.isUp()) mNrRavageTF++;

		// Stampede Ravage does not consume OoC.
		if (isStampedeUp) {
			mRavageEnergy += mState.onEnergyConsumer(cost);
		} else {
			if (mState.mOocEv.isUp()) mNrRavageOoC++;
			mRavageEnergy += mState.onOoCConsumer(cost);
		}

		mState.logResourceChange(prevEnergy, prevCps);

		return 1.0;
	}

	long mRavageDamage;
	int mNrRavageMiss;
	int mNrRavageDodge;
	int mNrRavageParry;
	int mNrRavageHit;
	int mNrRavageCrit;
	int mNrRavageTF;
	int mNrRavageOoC;
	int mRavageEnergy;
}
